﻿Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Reflection
Imports System.Runtime.InteropServices
Imports System.Xml

Namespace System.Workflow.ComponentModel.Serialization
    Friend Class DictionaryMarkupSerializer
        Inherits WorkflowMarkupSerializer
        ' Methods
        Protected Friend Overrides Sub AddChild(ByVal serializationManager As WorkflowMarkupSerializationManager, ByVal parentObj As Object, ByVal childObj As Object)
            If (parentObj Is Nothing) Then
                Throw New ArgumentNullException("parentObj")
            End If
            If (childObj Is Nothing) Then
                Throw New ArgumentNullException("childObj")
            End If
            Dim dictionary As IDictionary = [TryCast](parentObj,IDictionary)
            If (dictionary Is Nothing) Then
                Throw New InvalidOperationException(SR.GetString("Error_DictionarySerializerNonDictionaryObject"))
            End If
            Dim key As Object = Nothing
            Dim entry As DictionaryEntry
            For Each entry In Me.keylookupDictionary
                If ((entry.Value.GetType.IsValueType OrElse (Not entry.Value Is childObj)) AndAlso (Not entry.Value.GetType.IsValueType OrElse Not entry.Value.Equals(childObj))) Then
                    [Continue] For
                End If
                key = entry.Key
                Exit For
            Next
            If (key Is Nothing) Then
                Throw New InvalidOperationException(SR.GetString("Error_DictionarySerializerKeyNotFound", New Object() { childObj.GetType.FullName }))
            End If
            dictionary.Add(key, childObj)
            Me.keylookupDictionary.Remove(key)
        End Sub

        Protected Friend Overrides Sub ClearChildren(ByVal serializationManager As WorkflowMarkupSerializationManager, ByVal deserializedObject As Object)
            If (deserializedObject Is Nothing) Then
                Throw New ArgumentNullException("deserializedObject")
            End If
            Dim dictionary As IDictionary = [TryCast](deserializedObject,IDictionary)
            If (dictionary Is Nothing) Then
                Throw New InvalidOperationException(SR.GetString("Error_DictionarySerializerNonDictionaryObject"))
            End If
            dictionary.Clear
        End Sub

        Protected Friend Overrides Function GetChildren(ByVal serializationManager As WorkflowMarkupSerializationManager, ByVal obj As Object) As IList
            Dim dictionary As IDictionary = [TryCast](obj,IDictionary)
            If (dictionary Is Nothing) Then
                Throw New InvalidOperationException(SR.GetString("Error_DictionarySerializerNonDictionaryObject"))
            End If
            Dim list As New List([Of] Object)
            Dim entry As DictionaryEntry
            For Each entry In dictionary
                list.Add(entry)
            Next
            Return list
        End Function

        Friend Overrides Function GetExtendedProperties(ByVal manager As WorkflowMarkupSerializationManager, ByVal extendee As Object) As ExtendedPropertyInfo()
            Dim list As New List([Of] ExtendedPropertyInfo)
            Dim nullable As Nullable([Of] DictionaryEntry) = Nothing
            If (Not manager.WorkflowMarkupStack.Item(GetType(DictionaryEntry)) Is Nothing) Then
                nullable = New Nullable([Of] DictionaryEntry)(DirectCast(manager.WorkflowMarkupStack.Item(GetType(DictionaryEntry)), DictionaryEntry))
            End If
            If (Me.deserializingDictionary OrElse (nullable.HasValue AndAlso (nullable.Value.Value Is extendee))) Then
                Dim item As New ExtendedPropertyInfo(GetType(DictionaryEntry).GetProperty("Key", (BindingFlags.Public Or BindingFlags.Instance)), New GetValueHandler(AddressOf Me.OnGetKeyValue), New SetValueHandler(AddressOf Me.OnSetKeyValue), New GetQualifiedNameHandler(AddressOf Me.OnGetXmlQualifiedName), manager)
                list.Add(item)
            End If
            Return list.ToArray
        End Function

        Protected Friend Overrides Function GetProperties(ByVal serializationManager As WorkflowMarkupSerializationManager, ByVal obj As Object) As PropertyInfo()
            Return New PropertyInfo(0  - 1) {}
        End Function

        Protected Overrides Sub OnAfterDeserialize(ByVal serializationManager As WorkflowMarkupSerializationManager, ByVal obj As Object)
            MyBase.OnAfterDeserialize(serializationManager, obj)
            serializationManager.ExtendedPropertiesProviders.Remove(Me)
            Me.keylookupDictionary = Nothing
            Me.deserializingDictionary = False
        End Sub

        Protected Overrides Sub OnAfterSerialize(ByVal serializationManager As WorkflowMarkupSerializationManager, ByVal obj As Object)
            MyBase.OnAfterSerialize(serializationManager, obj)
            serializationManager.ExtendedPropertiesProviders.Remove(Me)
            Me.keylookupDictionary = Nothing
        End Sub

        Friend Overrides Sub OnBeforeDeserializeContents(ByVal serializationManager As WorkflowMarkupSerializationManager, ByVal obj As Object)
            MyBase.OnBeforeDeserializeContents(serializationManager, obj)
            serializationManager.ExtendedPropertiesProviders.Add(Me)
            Me.keylookupDictionary = New Hashtable
            Me.deserializingDictionary = True
        End Sub

        Friend Overrides Sub OnBeforeSerializeContents(ByVal serializationManager As WorkflowMarkupSerializationManager, ByVal obj As Object)
            MyBase.OnBeforeSerializeContents(serializationManager, obj)
            serializationManager.ExtendedPropertiesProviders.Add(Me)
            Me.keylookupDictionary = New Hashtable
        End Sub

        Private Function OnGetKeyValue(ByVal extendedProperty As ExtendedPropertyInfo, ByVal extendee As Object) As Object
            Dim nullable As Nullable([Of] DictionaryEntry) = Nothing
            If (Not extendedProperty.SerializationManager.WorkflowMarkupStack.Item(GetType(DictionaryEntry)) Is Nothing) Then
                nullable = New Nullable([Of] DictionaryEntry)(DirectCast(extendedProperty.SerializationManager.WorkflowMarkupStack.Item(GetType(DictionaryEntry)), DictionaryEntry))
            End If
            If (nullable.HasValue AndAlso (nullable.Value.Value Is extendee)) Then
                Return nullable.Value.Key
            End If
            Return Nothing
        End Function

        Private Function OnGetXmlQualifiedName(ByVal extendedProperty As ExtendedPropertyInfo, ByVal manager As WorkflowMarkupSerializationManager, <Out> ByRef prefix As String) As XmlQualifiedName
            prefix = "x"
            Return New XmlQualifiedName(extendedProperty.Name, "http://schemas.microsoft.com/winfx/2006/xaml")
        End Function

        Private Sub OnSetKeyValue(ByVal extendedProperty As ExtendedPropertyInfo, ByVal extendee As Object, ByVal value As Object)
            If (((Not extendee Is Nothing) AndAlso (Not value Is Nothing)) AndAlso Not Me.keylookupDictionary.Contains(value)) Then
                Me.keylookupDictionary.Add(value, extendee)
            End If
        End Sub

        Protected Friend Overrides Function ShouldSerializeValue(ByVal serializationManager As WorkflowMarkupSerializationManager, ByVal value As Object) As Boolean
            If (value Is Nothing) Then
                Return False
            End If
            If Not TypeOf value Is IDictionary Then
                Throw New InvalidOperationException(SR.GetString("Error_DictionarySerializerNonDictionaryObject"))
            End If
            Return (DirectCast(value, IDictionary).Count > 0)
        End Function


        ' Fields
        Private deserializingDictionary As Boolean
        Private keylookupDictionary As IDictionary
    End Class
End Namespace

